package com.gzhryc.net_marketing.cloud.account.services;

import com.gzhryc.common.IDTools;
import com.gzhryc.common.StringTools;
import com.gzhryc.common.event.DelayHandleService;
import com.gzhryc.common.exceptions.LogicException;
import com.gzhryc.common.logging.Logger;
import com.gzhryc.jdbc.Conditions;
import com.gzhryc.jdbc.JdbcSession;
import com.gzhryc.jdbc.MultiDBTools;
import com.gzhryc.net_marketing.cloud.business.dao.db.CloudGoodsPayOrder;
import com.gzhryc.net_marketing.cloud.business.services.CloudGoodsPayOrderService;
import com.gzhryc.net_marketing.core.enums.CloudPayAccountEnum;
import com.gzhryc.shared_device.base.enums.EPayState;
import com.gzhryc.net_marketing.api.protocol.account.CloudPayNotifyRequest;
import com.gzhryc.net_marketing.cloud.MarketConstants;
import com.gzhryc.net_marketing.cloud.account.callback.CloudPayNotifyCallbackDelayEvent;
import com.gzhryc.net_marketing.cloud.account.dao.CloudPayAccountExpenditureOrderDao;
import com.gzhryc.net_marketing.cloud.account.dao.db.CloudPayAccount;
import com.gzhryc.net_marketing.cloud.account.dao.db.CloudPayAccountExpenditureOrder;
import com.gzhryc.net_marketing.cloud.account.dao.enums.CloudPayAccountExpenditureOrderEnum;
import com.gzhryc.net_marketing.cloud.account.services.dto.CloudPayAccountExpenditureOrderSearch;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;

public class CloudPayAccountExpenditureOrderService {

    static Logger log = Logger.getLogger(CloudPayAccountExpenditureOrderService.class);

    public static CloudPayAccountExpenditureOrderService self() {
        return MultiDBTools.getService(MarketConstants.JDBC_KEY,CloudPayAccountExpenditureOrderService.class, true);
    }

    CloudPayAccountExpenditureOrderDao dao;

    public CloudPayAccountExpenditureOrderService(String jdbcKey) {
        this.dao = new CloudPayAccountExpenditureOrderDao(jdbcKey);
    }

    public List<CloudPayAccountExpenditureOrder> findBySearch(CloudPayAccountExpenditureOrderSearch search,Integer pageNo,Integer pageLimit){
        Conditions conditions = dao.buildConditions(search);
        conditions.desc("createDate");
        try {
            return dao.findByCondition(conditions,pageNo,pageLimit);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return null;
    }

    public Long countBySearch(CloudPayAccountExpenditureOrderSearch search){
        Conditions conditions = dao.buildConditions(search);
        try {
            return dao.count(conditions);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return 0L;
    }

    public CloudPayAccountExpenditureOrder getByTradeNo(String tradeNo){
        try {
            return dao.getById(tradeNo);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return null;
    }

    public CloudPayAccountExpenditureOrder getByBusinessTradeNo(String businessTradeNo){
        if(StringTools.isNotBlank(businessTradeNo)){
            Conditions conditions = new Conditions(CloudPayAccountExpenditureOrder.class);
            conditions.and().is("businessTradeNo",businessTradeNo);
            try {
                return dao.get(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public boolean createAndPay(CloudPayAccountExpenditureOrder expenditureOrder,CloudPayAccount payerAccount) throws LogicException {
        if(payerAccount.getMoney() < expenditureOrder.getMoney()){
            throw new LogicException("支付者账号资金不足");
        }
        CloudPayAccount payeeAccount = CloudPayAccountService.self().getById(expenditureOrder.getPayeeAccountId());
        if(payeeAccount == null){
            throw new LogicException("收款者账号不存在");
        }

        expenditureOrder.setTradeNo(expenditureOrder.getAccountId() + IDTools.getTimestampNanoID());
        if(StringTools.isBlank(expenditureOrder.getNotifyUrl())){
            expenditureOrder.setNotifyUrl(payerAccount.getPayNotifyUrl());
        }
        expenditureOrder.setPayeeNotifyUrl(payeeAccount.getPayNotifyUrl());
        expenditureOrder.setState(CloudPayAccountExpenditureOrderEnum.State.Settlement.index());
        expenditureOrder.setCreateDate(new Date());
        expenditureOrder.setPayDate(new Date());

        boolean isSuccess = false;
        JdbcSession.begin();
        try {
            if (dao.insert(expenditureOrder) > 0) {
                if (CloudPayAccountService.self().reduceMoney(payerAccount, expenditureOrder.getMoney(), expenditureOrder.getTradeNo()
                        , expenditureOrder.getTitle())) {
                    if (CloudPayAccountService.self().incomeFreezeMoney(payeeAccount, expenditureOrder.getMoney(), expenditureOrder.getTradeNo()
                            , expenditureOrder.getTitle())) {
                        JdbcSession.commit();
                        isSuccess = true;
                    }
                }
            }
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        } finally {
            JdbcSession.end();
        }

        if(isSuccess){
            expenditureOrder = this.getByTradeNo(expenditureOrder.getTradeNo());
            //处理云端订单
            if(CloudPayAccountEnum.BusinessType.GoodsOrderPay.name().equals(expenditureOrder.getBusinessType())) {
                CloudGoodsPayOrderService.self().updatePayTradeNo(expenditureOrder.getBusinessTradeNo()
                        , expenditureOrder.getTradeNo());
            }
            callback(expenditureOrder,payerAccount,payeeAccount,EPayState.Success.index());
            return true;
        }
        return false;
    }

    public boolean pay(CloudPayAccountExpenditureOrder expenditureOrder,CloudPayAccount payerAccount) throws LogicException {
        if(expenditureOrder != null && CloudPayAccountExpenditureOrderEnum.State.WaitPay.index().equals(expenditureOrder.getState())) {
            if(payerAccount.getMoney() < expenditureOrder.getMoney()){
                throw new LogicException("支付者账号资金不足");
            }
            CloudPayAccount payeeAccount = CloudPayAccountService.self().getById(expenditureOrder.getPayeeAccountId());
            if(payeeAccount == null){
                throw new LogicException("收款者账号不存在");
            }

            Conditions conditions = new Conditions(CloudPayAccountExpenditureOrder.class);
            conditions.and().is("tradeNo", expenditureOrder.getTradeNo());
            conditions.and().is("state",CloudPayAccountExpenditureOrderEnum.State.WaitPay.index());

            CloudPayAccountExpenditureOrder updateEntity = new CloudPayAccountExpenditureOrder();
            updateEntity.setState(CloudPayAccountExpenditureOrderEnum.State.Settlement.index());

            boolean isSuccess = false;
            JdbcSession.begin();
            try {
                if (dao.updateNotNull(updateEntity,conditions) > 0) {
                    if (CloudPayAccountService.self().reduceMoney(payerAccount, expenditureOrder.getMoney(), expenditureOrder.getTradeNo()
                            , expenditureOrder.getTitle())) {
                        if (CloudPayAccountService.self().incomeFreezeMoney(payeeAccount, expenditureOrder.getMoney(), expenditureOrder.getTradeNo()
                                , expenditureOrder.getTitle())) {
                            JdbcSession.commit();
                            isSuccess = true;
                        }
                    }
                }
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            } finally {
                JdbcSession.end();
            }

            if(isSuccess){
                expenditureOrder = this.getByTradeNo(expenditureOrder.getTradeNo());
                //处理云端订单
                if(CloudPayAccountEnum.BusinessType.GoodsOrderPay.name().equals(expenditureOrder.getBusinessType())) {
                    CloudGoodsPayOrderService.self().updatePayTradeNo(expenditureOrder.getBusinessTradeNo()
                            , expenditureOrder.getTradeNo());
                }
                callback(expenditureOrder,payerAccount,payeeAccount,EPayState.Success.index());
                return true;
            }
        }
        return false;
    }

    public boolean settlement(CloudPayAccountExpenditureOrder expenditureOrder,Integer operatorType,String operatorName,String reason) throws LogicException {
        CloudPayAccount payeeAccount = CloudPayAccountService.self().getById(expenditureOrder.getPayeeAccountId());
        if(payeeAccount == null){
            throw new LogicException("未找到收款账号");
        }

        if(payeeAccount.getFreezeMoney() < expenditureOrder.getMoney()){
            throw new LogicException("收款账号冻结金额不足");
        }

        CloudPayAccount payerAccount = CloudPayAccountService.self().getById(expenditureOrder.getAccountId());
        if(payerAccount == null){
            throw new LogicException("未找到支付账号");
        }

        Conditions conditions = new Conditions(CloudPayAccountExpenditureOrder.class);
        conditions.and().is("tradeNo",expenditureOrder.getTradeNo());
        conditions.and().is("state",CloudPayAccountExpenditureOrderEnum.State.Settlement.index());

        CloudPayAccountExpenditureOrder updateEntity = new CloudPayAccountExpenditureOrder();
        updateEntity.setState(CloudPayAccountExpenditureOrderEnum.State.Finish.index());
        updateEntity.setSettlementDate(new Date());

        if(StringTools.isBlank(expenditureOrder.getNotifyUrl())){
            updateEntity.setNotifyUrl(payerAccount.getPayNotifyUrl());
        }
        if(StringTools.isBlank(expenditureOrder.getPayeeNotifyUrl())){
            updateEntity.setPayeeNotifyUrl(payeeAccount.getPayNotifyUrl());
        }

        boolean isSuccess = false;
        JdbcSession.begin();
        try{
            if(dao.updateNotNull(updateEntity,conditions) > 0){
                if(CloudPayAccountService.self().unfreezeMoney(payeeAccount,expenditureOrder.getMoney()
                        , operatorType,operatorName,reason)){
                    JdbcSession.commit();
                    isSuccess = true;
                }
            }
        }catch (SQLException e){
            log.error(e.getMessage(),e);
        } finally {
            JdbcSession.end();
        }

        if(isSuccess){
            expenditureOrder = this.getByTradeNo(expenditureOrder.getTradeNo());
            callback(expenditureOrder,payerAccount,payeeAccount,EPayState.Success.index());
            return true;
        }
        return false;
    }

    public void callback(String tradeNo) throws LogicException {
        CloudPayAccountExpenditureOrder expenditureOrder = getByTradeNo(tradeNo);
        if(expenditureOrder == null){
            throw new LogicException("未找到交易订单");
        }

        Integer payResult = null;
        if(CloudPayAccountExpenditureOrderEnum.State.Settlement.index().equals(expenditureOrder.getState())
            || CloudPayAccountExpenditureOrderEnum.State.Finish.index().equals(expenditureOrder.getState())) {
            payResult = EPayState.Success.index();
        }else if(CloudPayAccountExpenditureOrderEnum.State.Close.index().equals(expenditureOrder.getState())){
            payResult = EPayState.Close.index();
        }

        if(payResult == null){
            throw new LogicException("当前状态无需回调");
        }

        CloudPayAccount payerAccount = CloudPayAccountService.self().getById(expenditureOrder.getAccountId());
        if(payerAccount == null){
            throw new LogicException("支付者账号不存在");
        }

        CloudPayAccount payeeAccount = CloudPayAccountService.self().getById(expenditureOrder.getPayeeAccountId());
        if(payeeAccount == null){
            throw new LogicException("收款者账号不存在");
        }

        boolean isSuccess = false;

        if(StringTools.isNotBlank(payerAccount.getPayNotifyUrl())){
            if(StringTools.isBlank(expenditureOrder.getNotifyUrl()) || !expenditureOrder.getNotifyUrl().equals(payerAccount.getPayNotifyUrl())){
                isSuccess = true;
            }
        }
        if(StringTools.isNotBlank(payeeAccount.getPayNotifyUrl())){
            if(StringTools.isBlank(expenditureOrder.getPayeeNotifyUrl()) || !expenditureOrder.getPayeeNotifyUrl().equals(payeeAccount.getPayNotifyUrl())){
                isSuccess = true;
            }
        }

        if(isSuccess) {
            CloudPayAccountExpenditureOrder updateEntity = new CloudPayAccountExpenditureOrder();
            updateEntity.setTradeNo(tradeNo);
            updateEntity.setNotifyUrl(payerAccount.getPayNotifyUrl());
            updateEntity.setPayeeNotifyUrl(payeeAccount.getPayNotifyUrl());
            try {
                if (dao.updateNotNull(updateEntity) > 0) {
                    expenditureOrder.setNotifyUrl(updateEntity.getNotifyUrl());
                    expenditureOrder.setPayeeNotifyUrl(updateEntity.getPayeeNotifyUrl());
                }
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }

        callback(expenditureOrder,payerAccount,payeeAccount,payResult);

    }

    private void callback(CloudPayAccountExpenditureOrder expenditureOrder,CloudPayAccount payerAccount,CloudPayAccount payeeAccount,Integer payResult){
        //触发回调程序
        CloudPayNotifyRequest notifyRequest = new CloudPayNotifyRequest();
        notifyRequest.getBody().setTradeNo(expenditureOrder.getTradeNo());
        notifyRequest.getBody().setBusinessType(expenditureOrder.getBusinessType());

        notifyRequest.getBody().setPayResult(payResult);
        notifyRequest.getBody().setMoney(expenditureOrder.getMoney());
        notifyRequest.getBody().setAccountId(payeeAccount.getId().toString());  //收款者账号
        notifyRequest.getBody().setPayerId(payerAccount.getId().toString());
        notifyRequest.getBody().setTitle(expenditureOrder.getTitle());
        notifyRequest.getBody().setExtContent(expenditureOrder.getExtContent());

        if (StringTools.isNotBlank(expenditureOrder.getNotifyUrl())) {
            notifyRequest.getBody().setBusinessTradeNo(expenditureOrder.getBusinessTradeNo());
            CloudPayNotifyCallbackDelayEvent payerEvent =
                    new CloudPayNotifyCallbackDelayEvent(expenditureOrder.getNotifyUrl(), notifyRequest);
            DelayHandleService.get().addEvent(payerEvent);
            log.info("触发支付者支付成功回调，路径：{{0}}，回调信息：{{1:json}}", expenditureOrder.getNotifyUrl(), notifyRequest);
        }

        if (StringTools.isNotBlank(expenditureOrder.getPayeeNotifyUrl())) {
            CloudGoodsPayOrder supplierGoodsOrder = CloudGoodsPayOrderService.self().getByTradeNo(expenditureOrder.getBusinessTradeNo());
            if(supplierGoodsOrder != null) {
                notifyRequest.getBody().setBusinessTradeNo(supplierGoodsOrder.getSupplierTradeNo());
                CloudPayNotifyCallbackDelayEvent payeeEvent =
                        new CloudPayNotifyCallbackDelayEvent(expenditureOrder.getPayeeNotifyUrl(), notifyRequest);
                DelayHandleService.get().addEvent(payeeEvent);
                log.info("触发收款者支付成功回调，路径：{{0}}，回调信息：{{1:json}}", expenditureOrder.getPayeeNotifyUrl(), notifyRequest);
            }else{
                log.error("未获取云商品订单信息，发送收款者通知失败，支付信息：{{0:json}}",expenditureOrder);
            }
        }
    }
}
